namespace Technique
{
	class TCoordinateAxes : public TObject, virtual public IDK::IRenderable
	{
		IDKClass;
	public:
		virtual void Reset(ref<IDK::IRenderState> rndState)
		{
			//empty
		}

		virtual bool Draw(ref<IDK::IRenderState> rndState)
		{
			//rndState->DrawAxis();
			return true;
		}

		virtual void Drawed(ref<IDK::IRenderState> rndState)
		{
			//empty
		}

		virtual void UnloadUnreferenced(ref<IDK::IRenderState> rndState)
		{
			//empty
		}
	};

	template<typename T>
	class TVertexBuffer : public TObject, virtual public IDK::IVertexBuffer
	{
		IDKClass;
	public:
		typedef DynamicArray<T> VertexData;

		TVertexBuffer(uint16 count) : mCount(count)
		{
			mVertexData = new VertexData::Create(mCount);
		}
	public:
		virtual Handle GetVertexBufferHandle(void)
		{
			return mHandle;
		}

		virtual void SetVertexBufferHandle(Handle handleId)
		{
			mHandle = handleId;
		}

		virtual uint GetVertexCount(void)
		{
			return mCount;
		}

		virtual uint GetVertexSize(void)
		{
			return sizeof(T);
		}

		virtual HandlePtr GetVertexData(void)
		{
			return mVertexData.As<THandlePtr>();;
		}

		T& GetVertex(uint16 index)
		{
			return mVertexData[index];
		}
	private:
		VertexData mVertexData;
		Handle mHandle;
		uint16 mCount;
	};

	class TGrid2D : public TObject, virtual public IDK::IRenderable
	{
		IDKClass;
	public:
		struct VertexAttrib
		{
			Math::Vector3 position;
		};
		typedef ref<TVertexBuffer<VertexAttrib>> VertexBuffer;

		TGrid2D(ref<IDK::IShaderProgram> shader, uint16 sizeX = 64, uint16 sizeY = 64)
			: mShader(shader)
		{

			mVertexBuffer = new VertexBuffer::Create((sizeX * 2) + (sizeY * 2));

			float halfSizeZ = sizeY / 2.0f;

			for(uint16 z = 0; z != sizeY; ++z)
			{
				{
					VertexAttrib& attrib = mVertexBuffer->GetVertex(z * 2);
					attrib.position.x = -halfSizeZ;
					attrib.position.z = (-halfSizeZ) + z;
				}

				{
					VertexAttrib& attrib = mVertexBuffer->GetVertex((z * 2) + 1);
					attrib.position.x = halfSizeZ - 1;
					attrib.position.z = (-halfSizeZ) + z;
				}
			}

			float halfSizeX = sizeX / 2.0f;

			for(uint16 x = 0; x != sizeX; ++x)
			{
				{
					VertexAttrib& attrib = mVertexBuffer->GetVertex((sizeY * 2) + x * 2);
					attrib.position.z = -halfSizeX;
					attrib.position.x = -halfSizeX + x;
				}

				{
					VertexAttrib& attrib = mVertexBuffer->GetVertex((sizeY * 2) + (x * 2) + 1);
					attrib.position.z = halfSizeX - 1;
					attrib.position.x = (-halfSizeX) + x;
				}
			}
		}

		virtual void Reset(ref<IDK::IRenderState> rndState)
		{
			//shader reset
			mShader->Reset(rndState);

			//reset vertex buffer
			rndState->UnLoadVertexBuffer(mVertexBuffer.As<IDK::IVertexBuffer>());
		}

		virtual bool Draw(ref<IDK::IRenderState> rndState)
		{
			mShader->Draw(rndState);

			rndState->SetIndexBuffer(NullPtr);
			rndState->SetVertexBuffer(mVertexBuffer.As<IDK::IVertexBuffer>());
			
			rndState->DrawVertexData(IDK::IRenderState::PrimitiveType::Lines);
			return true;
		}

		virtual void Drawed(ref<IDK::IRenderState> rndState)
		{
			//empty
		}

		virtual void UnloadUnreferenced(ref<IDK::IRenderState> rndState)
		{
			//empty
		}
	private:
		VertexBuffer mVertexBuffer;
		ref<IDK::IShaderProgram> mShader;
	};

	typedef TStaticArray<float, 16> TLightMatrix; 

	class TSunCamera : public TBasicCamera
	{
		typedef TBasicCamera Base;
	public:
		TSunCamera(ref<IDK::ICamera> viewCam);
	protected:
		virtual void CalculateMatrix(IDK::ICamera::MatrixMode::Enum mode, Math::Matrix44& dest);
	private:
		ref<IDK::ICamera> mViewCam;
	};

	class TSunShadowPass : public TObject, virtual public IDK::IRenderContext::IPass
	{
		IDKClass;
	public:
		enum Constant
		{
			UpdateShadowFrame = 1
		};
		TSunShadowPass(
			ref<IDK::IScene> scene,
			ref<IDK::ICamera> sunCam,
			ref<IDK::ICamera> viewCam,
			ref<IDK::IShaderProgram> programShadow,
			ref<IDK::IRenderTarget> shadowRT,
			ref<TLightMatrix> lightMatrix);

		virtual void Reset(ref<IDK::IRenderState> rndState);
		virtual bool Draw(ref<IDK::IRenderState> rndState);
		virtual void Drawed(ref<IDK::IRenderState> rndState);
	protected:
		ref<IDK::IScene> mScene;
		ref<IDK::IShaderProgram> mProgramShadow;
		ref<IDK::IRenderTarget> mShadowRT;
		ref<IDK::ICamera> mSunCamera;
		ref<IDK::ICamera> mViewCamera;
		StaticArray<float, 16> mLightMatrix;
		Math::Vector3 mUpdatePos;
		uint mFrameToUpdate;
	};

	class TOutputScreenPass : public TObject, virtual public IDK::IRenderContext::IPass
	{
		IDKClass;
	public:
		typedef TStaticArray<float, 2> BlurParameter;
	public:
		TOutputScreenPass(ref<IDK::IRenderTarget> output,
			ref<IDK::IRenderTarget> temp1,
			ref<IDK::IRenderTarget> temp2,
			ref<IDK::IShaderProgram> downProgram,
			ref<IDK::IShaderProgram> highProgram,
			ref<IDK::IShaderProgram> blurProgram,
			ref<IDK::IShaderProgram> finalProgram,
			ref<BlurParameter> blurOffsetParameter);

		virtual void Reset(ref<IDK::IRenderState> rndState);
		virtual bool Draw(ref<IDK::IRenderState> rndState);
		virtual void Drawed(ref<IDK::IRenderState> rndState);
	private:
		ref<IDK::IShaderProgram> mProgramDown;
		ref<IDK::IShaderProgram> mProgramHigh;
		ref<IDK::IShaderProgram> mProgramBlur;
		ref<IDK::IShaderProgram> mProgramFinal;
		ref<IDK::IRenderTarget> mOutput;
		ref<IDK::IRenderTarget> mTemp1;
		ref<IDK::IRenderTarget> mTemp2;
		StaticArray<float, 2> mBlurOffsetParameter;
	};

	class TDeferredShadingPass : public TObject, virtual public IDK::IRenderContext::IPass
	{
		IDKClass;
	public:
		TDeferredShadingPass(
			ref<IDK::IScene> scene,
			ref<IDK::ICamera> cam,
			ref<IDK::IRenderTarget> gBuffer,
			ref<IDK::IRenderTarget> shadow,
			ref<IDK::IRenderTarget> output,
			ref<IDK::IShaderProgram> program);

		virtual void Reset(ref<IDK::IRenderState> rndState);
		virtual bool Draw(ref<IDK::IRenderState> rndState);
		virtual void Drawed(ref<IDK::IRenderState> rndState);
	private:
		ref<IDK::IShaderProgram> mProgram;
		ref<IDK::IRenderTarget> mGBuffer;
		ref<IDK::IRenderTarget> mOutput;
		ref<IDK::IRenderTarget> mShadow;
		ref<IDK::IScene> mScene;
		ref<IDK::ICamera> mCamera;
	};

	class TForwardShadingPass : public TObject, virtual public IDK::IRenderContext::IPass
	{
		IDKClass;
	public:
		TForwardShadingPass(
			ref<IDK::IScene> scene,
			ref<IDK::ICamera> cam,
			ref<IDK::IRenderTarget> shadow, 
			ref<IDK::IRenderTarget> output);

		virtual void Reset(ref<IDK::IRenderState> rndState);
		virtual bool Draw(ref<IDK::IRenderState> rndState);
		virtual void Drawed(ref<IDK::IRenderState> rndState);
	private:
		ref<IDK::IRenderTarget> mOutput;
		ref<IDK::IRenderTarget> mShadow;
		ref<IDK::IScene> mScene;
		ref<IDK::ICamera> mCamera;
	};

	class TDebugShadingScreenPass : public TObject, virtual public IDK::IRenderContext::IPass
	{
		IDKClass;
	public:
		TDebugShadingScreenPass(ref<IDK::IRenderTarget> input, ref<IDK::IShaderProgram> program);
		virtual void Reset(ref<IDK::IRenderState> rndState);
		virtual bool Draw(ref<IDK::IRenderState> rndState);
		virtual void Drawed(ref<IDK::IRenderState> rndState);
	private:
		ref<IDK::IRenderTarget> mInput;
		ref<IDK::IShaderProgram> mProgram;
	};

	class TDebugShadingBufferPass : public TObject, virtual public IDK::IRenderContext::IPass
	{
		IDKClass;
	public:
		TDebugShadingBufferPass(
			ref<IDK::IScene> scene,
			ref<IDK::ICamera> cam);

		virtual void Reset(ref<IDK::IRenderState> rndState);
		virtual bool Draw(ref<IDK::IRenderState> rndState);
		virtual void Drawed(ref<IDK::IRenderState> rndState);
	private:
		ref<IDK::IScene> mScene;
		ref<IDK::ICamera> mCamera;
	};
}